<template>
<div class="products-page">
<div class="toolbar card">
<el-input v-model="filters.keyword" placeholder="搜索商品"
prefix-icon="el-icon-search" clearable @clear="onSearch" @keyup.enter="onSearch"/>
<el-select v-model="filters.sortKey" placeholder="排序字段" @change="onSearch">
<el-option label="价格" value="price"/><el-option label="库存" value="stock"/>
</el-select>
<el-button v-ripple type="primary" icon="el-icon-plus" @click="openDialog('add')">
新增商品
</el-button>
</div>
<el-skeleton v-if="loading" :rows="4" animated class="card"/>
<el-table v-else :data="pagedGoods" stripe highlight-current-row class="card" @sort-change="onSortChange">
<el-table-column prop="id" label="ID" width="60"/>
<el-table-column label="图片" width="100">
<template slot-scope="{ row }">
<img :src="row.image" class="img-thumb"/>
</template>
</el-table-column>
<el-table-column prop="name" label="名称"/>
<el-table-column prop="price" label="价格" width="100" sortable="custom">
<template slot-scope="{ row }">
<el-tag type="success">¥{{row.price.toFixed(2)}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="stock" label="库存" width="80" sortable="custom"/>
<el-table-column label="操作" width="160">
<template slot-scope="{ row }">
<el-button v-ripple size="mini" @click="openDialog('edit',row)">编辑</el-button>
<el-button v-ripple size="mini" type="danger" @click="onDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination background layout="prev, pager, next"
:total="filtered.length" :page-size="pageSize" :current-page.sync="page"
@current-change="onPageChange" class="pagination"/>
<transition name="dialog-fade" appear>
<el-dialog :title="dialogMode==='add'?'新增商品':'编辑商品'"
:visible.sync="dialogVisible" width="400px" @open="resetFormIfAdd">
<el-form :model="form" label-width="80px">
<el-form-item label="名称"><el-input v-model="form.name"/></el-form-item>
<el-form-item label="价格"><el-input-number v-model.number="form.price" :min="0" :step="0.1"/></el-form-item>
<el-form-item label="库存"><el-input-number v-model.number="form.stock" :min="0"/></el-form-item>
<el-form-item label="图片"><el-input v-model="form.image" placeholder="填写 assets 下文件名"/></el-form-item>
</el-form>
<span slot="footer"><el-button @click="dialogVisible=false">取消</el-button>
<el-button type="primary" @click="onSave">保存</el-button>
</span>
</el-dialog>
</transition>
</div>
</template>

<script>
import { debounce } from 'lodash'
export default {
data(){
return {
list:[], loading:true, page:1, pageSize:6,
filters:{keyword:'',sortKey:''},
dialogVisible:false, dialogMode:'add',
form:{id:null,name:'',price:0,stock:0,image:''}
}
},
computed:{
filtered(){
let res=this.list
if(this.filters.keyword){
const kw=this.filters.keyword.toLowerCase()
res=res.filter(i=>i.name.toLowerCase().includes(kw))
}
if(this.filters.sortKey){
res=[...res].sort((a,b)=>a[this.filters.sortKey]-b[this.filters.sortKey])
}
return res
},
pagedGoods(){
const s=(this.page-1)*this.pageSize
return this.filtered.slice(s,s+this.pageSize)
}
},
created(){
setTimeout(()=>{
// 模拟15条初始数据（替换为实际）
this.list = [
{id:1,name:'苹果',price:4.5,stock:100,image:require('@/assets/apple.jpg')},
{id:2,name:'香蕉',price:3.2,stock:150,image:require('@/assets/banana.jpg')},
{id:3,name:'橙子',price:5.0,stock:120,image:require('@/assets/orange.jpg')},
{id:4,name:'葡萄',price:6.8,stock:80,image:require('@/assets/grape.jpg')},
{id:5,name:'西瓜',price:2.5,stock:60,image:require('@/assets/watermelon.jpg')},
{id:6,name:'菠萝',price:8.0,stock:50,image:require('@/assets/pineapple.jpg')},
{id:7,name:'草莓',price:15.0,stock:40,image:require('@/assets/strawberry.jpg')},
{id:8,name:'猕猴桃',price:9.0,stock:70,image:require('@/assets/kiwi.jpg')},
{id:9,name:'桃子',price:7.5,stock:90,image:require('@/assets/peach.jpg')},
{id:10,name:'柠檬',price:4.0,stock:110,image:require('@/assets/lemon.jpg')},
{id:11,name:'樱桃',price:18.0,stock:30,image:require('@/assets/cherry.jpg')},
{id:12,name:'蓝莓',price:20.0,stock:25,image:require('@/assets/blueberry.jpg')},
{id:13,name:'杏子',price:6.0,stock:80,image:require('@/assets/apricot.jpg')},
{id:14,name:'石榴',price:12.0,stock:55,image:require('@/assets/pomegranate.jpg')},
{id:15,name:'龙眼',price:14.0,stock:45,image:require('@/assets/longan.jpg')},
]
this.loading=false
},800)
},
methods:{
onSearch:debounce(function(){this.page=1},300),
onSortChange({prop,order}){this.filters.sortKey=prop; if(order==='descending') this.filtered.reverse()},
onPageChange(p){this.page=p},
openDialog(mode,row){
this.dialogMode=mode
this.form = mode==='edit'?{...row}:{id:null,name:'',price:0,stock:0,image:''}
this.dialogVisible=true
},
resetFormIfAdd(){ if(this.dialogMode==='add') this.form={id:null,name:'',price:0,stock:0,image:''} },
onSave(){
if(!this.form.name||!this.form.image){ this.$message.warning('请填写名称和图片');return }
if(this.dialogMode==='add'){
const id=this.list.length?Math.max(...this.list.map(i=>i.id))+1:1
const img=require(`@/assets/${this.form.image}`)
this.list.push({...this.form,id,image:img})
this.$notify({title:'成功',message:'新增成功',type:'success'})
} else {
const idx=this.list.findIndex(i=>i.id===this.form.id)
const img=require(`@/assets/${this.form.image}`)
this.list.splice(idx,1,{...this.form,image:img})
this.$notify({title:'成功',message:'更新成功',type:'success'})
}
this.dialogVisible=false
},
onDelete(id){
this.$confirm('确认删除？','提示',{type:'warning'})
.then(()=>{ this.list=this.list.filter(i=>i.id!==id);this.$notify({title:'成功',message:'删除成功',type:'success'}) })
.catch(()=>{})
}
}
}
</script>

<style scoped>
@import '@/assets/theme.css';
.products-page .toolbar{display:flex;gap:10px;align-items:center;background:var(--color-card-bg);padding:12px;border-radius:8px;box-shadow:0 2px 8px var(--color-card-shadow);}
.card{background:var(--color-card-bg);border-radius:8px;box-shadow:0 4px 12px var(--color-card-shadow);margin-top:20px;}
.pagination{margin-top:20px;text-align:right;}
.img-thumb{width:60px;height:60px;object-fit:cover;border-radius:4px;}
.dialog-fade-enter-active{animation:zoomIn .3s} .dialog-fade-leave-active{animation:zoomOut .3s}
@keyframes zoomIn{from{transform:scale(0.6);opacity:0}to{transform:scale(1);opacity:1}}@keyframes zoomOut{from{transform:scale(1);opacity:1}to{transform:scale(0.6);opacity:0}}
</style>